/*
 *  Copyright (C) 2009 Andrej Stepanchuk
 *  Copyright (C) 2009-2010 Howard Chu
 *
 *  This file is part of librtmp.
 *
 *  librtmp is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1,
 *  or (at your option) any later version.
 *
 *  librtmp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with librtmp see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *  http://www.gnu.org/copyleft/lgpl.html
 */

#include <stdlib.h>
#include <string.h>

#include <assert.h>
#include <ctype.h>

#include "rtmp_sys.h"
#include "log.h"

int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
	AVal *playpath, AVal *app)
{
	char *p, *end, *ques, *slash,*host_begin,* host_end;

	RTMP_Log(RTMP_LOGDEBUG, "Parsing...");

	*protocol = RTMP_PROTOCOL_RTMP;
	*port = 0;
	playpath->av_len = 0;
	playpath->av_val = NULL;
	app->av_len = 0;
	app->av_val = NULL;

	/* Old School Parsing */

	/* look for usual :// pattern */
	p = strstr(url, "://");
	if(!p) {
		RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
		return FALSE;
	}
	{
		int len = (int)(p-url);

		if(len == 4 && strncasecmp(url, "rtmp", 4)==0)
			*protocol = RTMP_PROTOCOL_RTMP;
		else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0)
			*protocol = RTMP_PROTOCOL_RTMPT;
		else if(len == 5 && strncasecmp(url, "rtmps", 5)==0)
			*protocol = RTMP_PROTOCOL_RTMPS;
		else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0)
			*protocol = RTMP_PROTOCOL_RTMPE;
		else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0)
			*protocol = RTMP_PROTOCOL_RTMFP;
		else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0)
			*protocol = RTMP_PROTOCOL_RTMPTE;
		else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0)
			*protocol = RTMP_PROTOCOL_RTMPTS;
		else {
			RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
			goto parsehost;
		}
	}

	RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);

parsehost:
	/* let's get the hostname */
	p+=3;

	/* check for sudden death */
	if(*p==0) {
		RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
		return FALSE;
	}

	end   = p + strlen(p);

	if (p[0] == '[')
	{
		p ++; /* skip '[' */
		host_begin = p;
		host_end = strchr (p, ']');
		if (host_end) {
			p = host_end; 
			p ++;/* skip ']' */
		}
		else {
			RTMP_Log(RTMP_LOGWARNING, "IPv6 Address Format Is Invalid!");
			return FALSE;
		}
	}
	else {
		//Note 2015-09-23: Fix stream name with ':',eg. rtmp://fso.hhp.9D48.zetacdn.net/209D48/mp4:testarnaud.mp4?sup0eY2eXG2rR7mf

		host_begin = p;
		
		while (*p) {
			if (*p == ':' || *p == '/') {
				host_end = p;
				break;
			}
			p ++;
		}

		if (!host_end) {
			RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
			host_end = end;
		}
		/* BUG code,not use
		host_end = strchr (p, ':');
		if (!host_end) {
			host_end = strchr(p, '/');
			if (!host_end) {
				RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
				host_end = end;
			}
		}
		*/
		p = host_end;
	}

	ques  = strchr(p, '?');
	slash = strchr(p, '/');
	
	{
		int hostlen;

		hostlen = (int)(host_end - host_begin);

		if(hostlen < 256) {
			host->av_val = host_begin;
			host->av_len = hostlen;
			RTMP_Log(RTMP_LOGDEBUG, "Parsed host    : %.*s", hostlen, host->av_val);
		} else {
			RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
		}
	}

	/* get the port number if available */
	if(*p == ':') {
		unsigned int p2;
		p++;
		p2 = atoi(p);
		if(p2 > 65535) {
			RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
		} else {
			*port = p2;
		}
	}

	if(!slash) {
		RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
		return TRUE;
	}
	p = slash+1;

	{
		/* parse application
		*
		* rtmp://host[:port]/app[/appinstance][/...]
		* application = app[/appinstance]
		*/

		char *slash2, *slash3 = NULL, *slash4 = NULL;
		int applen, appnamelen;

		slash2 = strchr(p, '/');
		if(slash2)
			slash3 = strchr(slash2+1, '/');
		if(slash3)
			slash4 = strchr(slash3+1, '/');

		applen = end-p; /* ondemand, pass all parameters as app */
		appnamelen = applen; /* ondemand length */

		if(ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */
			appnamelen = ques-p;
		}
		else if(strncmp(p, "ondemand/", 9)==0) {
			/* app = ondemand/foobar, only pass app=ondemand */
			applen = 8;
			appnamelen = 8;
		}
		else { /* app!=ondemand, so app is app[/appinstance] */
			if(slash4)
				appnamelen = slash4-p;
			else if(slash3)
				appnamelen = slash3-p;
			else if(slash2)
				appnamelen = slash2-p;

			applen = appnamelen;
		}

		app->av_val = p;
		app->av_len = applen;
		RTMP_Log(RTMP_LOGDEBUG, "Parsed app     : %.*s", applen, p);

		p += appnamelen;
	}

	if (*p == '/')
		p++;

	if (end-p) {
		AVal av = {p, end-p};
		RTMP_ParsePlaypath(&av, playpath);
	}

	return TRUE;
}

/*
* Extracts playpath from RTMP URL. playpath is the file part of the
* URL, i.e. the part that comes after rtmp://host:port/app/
*
* Returns the stream name in a format understood by FMS. The name is
* the playpath part of the URL with formatting depending on the stream
* type:
*
* mp4 streams: prepend "mp4:", remove extension
* mp3 streams: prepend "mp3:", remove extension
* flv streams: remove extension
*/
void RTMP_ParsePlaypath(AVal *in, AVal *out) {
	int addMP4 = 0;
	int addMP3 = 0;
	int subExt = 0;
	const char *playpath = in->av_val;
	const char *temp, *q, *ext = NULL;
	const char *ppstart = playpath;
	char *streamname, *destptr, *p;

	int pplen = in->av_len;

	out->av_val = NULL;
	out->av_len = 0;

	if ((*ppstart == '?') &&
		(temp=strstr(ppstart, "slist=")) != 0) {
			ppstart = temp+6;
			pplen = strlen(ppstart);

			temp = strchr(ppstart, '&');
			if (temp) {
				pplen = temp-ppstart;
			}
	}

	q = strchr(ppstart, '?');
	if (pplen >= 4) {
		if (q)
			ext = q-4;
		else
			ext = &ppstart[pplen-4];
		if ((strncmp(ext, ".f4v", 4) == 0) ||
			(strncmp(ext, ".mp4", 4) == 0)) {
				addMP4 = 1;
				subExt = 1;
				/* Only remove .flv from rtmp URL, not slist params */
		} else if ((ppstart == playpath) &&
			(strncmp(ext, ".flv", 4) == 0)) {
				subExt = 1;
		} else if (strncmp(ext, ".mp3", 4) == 0) {
			addMP3 = 1;
			subExt = 1;
		}
	}

	streamname = (char *)malloc((pplen+4+1)*sizeof(char));
	if (!streamname)
		return;

	destptr = streamname;
	if (addMP4) {
		if (strncmp(ppstart, "mp4:", 4)) {
			strcpy(destptr, "mp4:");
			destptr += 4;
		} else {
			subExt = 0;
		}
	} else if (addMP3) {
		if (strncmp(ppstart, "mp3:", 4)) {
			strcpy(destptr, "mp3:");
			destptr += 4;
		} else {
			subExt = 0;
		}
	}

	for (p=(char *)ppstart; pplen >0;) {
		/* skip extension */
		if (subExt && p == ext) {
			p += 4;
			pplen -= 4;
			continue;
		}
		if (*p == '%') {
			unsigned int c;
			sscanf(p+1, "%02x", &c);
			*destptr++ = c;
			pplen -= 3;
			p += 3;
		} else {
			*destptr++ = *p++;
			pplen--;
		}
	}
	*destptr = '\0';

	out->av_val = streamname;
	out->av_len = destptr - streamname;
}
